using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Terra.Data.Context;
using Terra.Data.Entities.Identity;
using Terra.Data.Extensions;
using Terra.Data.Models.Identity;

namespace Terra.Data.Repository.Identity;

/// <summary>
/// 菜单仓储实现
/// </summary>
public class MenuRepository : RepositoryBase<Menu, Guid>, IMenuRepository
{
    private readonly TerraDbContext _terraDbContext;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="context">数据库上下文</param>
    public MenuRepository(TerraDbContext context) : base(context)
    {
        _terraDbContext = context;
    }

    #region 基础查询

    /// <summary>
    /// 根据菜单名称查找菜单
    /// </summary>
    /// <param name="name">菜单名称</param>
    /// <returns>菜单实体</returns>
    public async Task<Menu> FindByNameAsync(string name)
    {
        return await _dbContext.Set<Menu>()
            .FirstOrDefaultAsync(x => x.Name == name);
    }

    /// <summary>
    /// 根据路径查找菜单
    /// </summary>
    /// <param name="path">路由路径</param>
    /// <returns>菜单实体</returns>
    public async Task<Menu> FindByPathAsync(string path)
    {
        return await _dbContext.Set<Menu>()
            .FirstOrDefaultAsync(x => x.Path == path && !string.IsNullOrEmpty(x.Path));
    }

    /// <summary>
    /// 获取全部菜单，按照排序号排序，并包含关联的权限信息
    /// </summary>
    /// <returns>所有菜单</returns>
    public async Task<List<Menu>> GetAllMenusAsync()
    {
        return await _dbContext.Set<Menu>()
            .Include(m => m.Permission)
            .OrderBy(m => m.Sort)
            .AsNoTracking()
            .ToListAsync();
    }

    /// <summary>
    /// 获取子菜单列表
    /// </summary>
    /// <param name="parentId">父菜单ID</param>
    /// <returns>子菜单列表</returns>
    public async Task<List<Menu>> GetChildrenAsync(Guid parentId)
    {
        return await _dbContext.Set<Menu>()
            .Where(m => m.ParentId == parentId)
            .OrderBy(m => m.Sort)
            .ToListAsync();
    }

    /// <summary>
    /// 获取菜单分页列表
    /// </summary>
    /// <param name="query">查询条件</param>
    /// <returns>菜单列表和总数</returns>
    public async Task<(List<Menu> Items, int TotalCount)> GetPagedMenusAsync(MenuQueryDto query)
    {
        var queryable = _dbContext.Set<Menu>().AsQueryable();

        // 按名称筛选
        if (!string.IsNullOrWhiteSpace(query.Name))
        {
            queryable = queryable.Where(m => m.Name.Contains(query.Name));
        }

        // 按类型筛选
        if (!string.IsNullOrWhiteSpace(query.Type))
        {
            queryable = queryable.Where(m => m.Type == query.Type);
        }

        // 按状态筛选
        if (query.Status.HasValue)
        {
            queryable = queryable.Where(m => m.Status == query.Status.Value);
        }

        // 获取总数
        var totalCount = await queryable.CountAsync();

        // 应用排序
        queryable = queryable.ApplyOrder(nameof(Menu.Sort));

        // 应用分页
        var items = await queryable
            .ApplyPaging(query.PageIndex, query.PageSize)
            .ToListAsync();

        return (items, totalCount);
    }

    /// <summary>
    /// 获取菜单详情
    /// </summary>
    /// <param name="id">菜单ID</param>
    /// <returns>菜单详情</returns>
    public async Task<Menu> GetMenuDetailAsync(Guid id)
    {
        return await _dbContext.Set<Menu>()
            .Include(m => m.Parent)
            .Include(m => m.Children)
            .Include(m => m.Permission)
            .FirstOrDefaultAsync(m => m.Id == id);
    }

    #endregion

    #region 数据验证

    /// <summary>
    /// 检查菜单名称是否已存在
    /// </summary>
    /// <param name="name">菜单名称</param>
    /// <param name="excludeMenuId">排除的菜单ID</param>
    /// <returns>是否存在</returns>
    public async Task<bool> ExistsByNameAsync(string name, Guid? excludeMenuId = null)
    {
        var query = _dbContext.Set<Menu>()
            .Where(m => m.Name == name);

        if (excludeMenuId.HasValue && excludeMenuId.Value != Guid.Empty)
        {
            query = query.Where(m => m.Id != excludeMenuId.Value);
        }

        return await query.AnyAsync();
    }

    /// <summary>
    /// 检查菜单路径是否已存在
    /// </summary>
    /// <param name="path">菜单路径</param>
    /// <param name="excludeMenuId">排除的菜单ID</param>
    /// <returns>是否存在</returns>
    public async Task<bool> ExistsByPathAsync(string path, Guid? excludeMenuId = null)
    {
        // 空路径无需检查重复
        if (string.IsNullOrEmpty(path))
        {
            return false;
        }

        var query = _dbContext.Set<Menu>()
            .Where(m => m.Path == path);

        if (excludeMenuId.HasValue && excludeMenuId.Value != Guid.Empty)
        {
            query = query.Where(m => m.Id != excludeMenuId.Value);
        }

        return await query.AnyAsync();
    }

    #endregion

    #region 数据操作

    /// <summary>
    /// 批量删除菜单
    /// </summary>
    /// <param name="menuIds">菜单ID列表</param>
    /// <returns>删除结果和失败ID列表</returns>
    public async Task<(bool Succeeded, List<Guid> FailedIds)> DeleteMenusAsync(IEnumerable<Guid> menuIds)
    {
        var ids = menuIds.ToList();
        var failedIds = new List<Guid>();

        // 查找要删除的菜单
        var menusToDelete = await _dbContext.Set<Menu>()
            .Where(m => ids.Contains(m.Id))
            .ToListAsync();

        // 检查每个菜单是否有子菜单
        foreach (var menuId in ids)
        {
            // 检查是否有子菜单
            var hasChildren = await _dbContext.Set<Menu>()
                .AnyAsync(m => m.ParentId == menuId);

            if (hasChildren)
            {
                failedIds.Add(menuId);
            }
        }

        // 过滤掉有子菜单的菜单
        var menus = menusToDelete.Where(m => !failedIds.Contains(m.Id)).ToList();

        if (menus.Any())
        {
            _dbContext.Set<Menu>().RemoveRange(menus);
            await _dbContext.SaveChangesAsync();
        }

        // 返回所有被请求删除但未在数据库中被删除的ID
        var deletedMenuIds = menus.Select(m => m.Id).ToList();
        failedIds.AddRange(ids.Except(deletedMenuIds).Except(failedIds));

        return (failedIds.Count == 0, failedIds);
    }

    #endregion
}